home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
PROGRAM
/
DDJ0992.ARJ
/
LISTING2.ASC
< prev
next >
Wrap
Text File
|
1992-08-10
|
16KB
|
717 lines
/*
** Desciption of AMD Am9513 registers and modes
*/
/* commands */
#define CMD_SET_DPR(element, group) (element | group)
#define CMD_ARM 0x20
#define CMD_LOAD 0x40
#define CMD_LOAD_AND_ARM 0x60
#define CMD_SAVE 0xA0
#define CMD_DISARM 0xC0
#define CMD_MASTER_RESET 0xFF
/* for specifying counters with commands */
#define CMD_COUNTER(n) (1 << (n-1))
/* element pointers for the Data Pointer Register */
#define ELEMENT_CMR 000
#define ELEMENT_CLR 010
#define ELEMENT_CHR 020
#define ELEMENT_CHR_ONLY 030
#define ELEMENT_AR1 000
#define ELEMENT_AR2 010
#define ELEMENT_MMR 020
#define ELEMENT_SR_ONLY 030
/* group pointers for the Data Pointer Register */
#define GROUP_CNTR(n) (n)
#define GROUP_CNTRL 007
/* master mode register settings */
#define MMR_SCALER_BINARY 0x0000
#define MMR_SCALER_BCD 0x8000
#define MMR_DP_INC 0x0000
#define MMR_DP_NOINC 0x4000
/* counter mode register settings */
#define CMR_GATE_NONE 0x0000
#define CMR_GATE_EDGE_HIGH 0xC000
#define CMR_EDGE_RISING 0x0000
#define CMR_EDGE_FALLING 0x1000
#define CMR_SOURCE_F1 0x0B00
#define CMR_SOURCE_F2 0x0C00
#define CMR_SOURCE_F3 0x0D00
#define CMR_SOURCE_F4 0x0E00
#define CMR_SOURCE_F5 0x0F00
#define CMR_COUNT_ONCE 0x0000
#define CMR_COUNT_REPEAT 0x0020
#define CMR_MODE_BINARY 0x0000
#define CMR_MODE_BCD 0x0010
#define CMR_DIR_DOWN 0x0000
#define CMR_DIR_UP 0x0008
#define CMR_OUT_INACTIVE_LOW 0x0000
#define CMR_OUT_PULSE_HIGH 0x0001
#define CMR_OUT_TOGGLE 0x0002
#define CMR_OUT_INACTIVE_HIGH 0x0004
#define CMR_OUT_PULSE_LOW 0x0005
#define am9513_reset(cmd_port) am9513_command(cmd_port, CMD_MASTER_RESET)
extern void am9513_command();
extern void am9513_output();
extern unsigned short am9513_input();
extern int am9513_set_period();
#define TIME_DRT 0
#define TIME_IST 1
#define TIME_INT 2
#define TIME_SYS 3
#define TIME_TRT 4
#define NUM_TIMES 5
extern unsigned short times[];
extern unsigned int overruns;
extern unsigned long period;
/*
** Routines for interfacing with the timer.
*/
#include <stdio.h>
#include <errno.h>
#include "timer.h"
#include "timer_ioctl.h"
static int fd;
unsigned long period;
unsigned short times[NUM_TIMES];
unsigned int overruns;
void init_timer(name, desired_period)
char *name;
unsigned long desired_period;
{
if ((fd = open(name, 0)) == -1) {
(void) fprintf(stderr, "open(%s): %s\n", name, CURERRMSG);
exit(1);
}
period = desired_period;
if (period) {
if (ioctl(fd, TIMER_PERIOD_SET, &period) == -1) {
perror("ioctl(TIMER_PERIOD_SET)");
exit(1);
}
} else {
if (ioctl(fd, TIMER_PERIOD_GET, &period) == -1) {
perror("ioctl(TIMER_PERIOD_GET)");
exit(1);
}
}
}
void wait_for_interrupt()
{
struct timer_measurements m;
int i;
if (ioctl(fd, TIMER_WAIT_FOR_INT, &m) == -1) {
perror("ioctl(TIMER_WAIT_FOR_INT)");
exit(1);
}
if (ioctl(fd, TIMER_READ, ×[TIME_TRT]) == -1) {
perror("ioctl(TIMER_READ)");
exit(1);
}
times[TIME_DRT] = m.drt;
times[TIME_IST] = m.ist;
times[TIME_INT] = m.drt + m.ist;
times[TIME_SYS] = times[TIME_TRT] - times[TIME_INT];
overruns = m.overruns;
}
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
static pthread_mutex_t mutex;
static pthread_cond_t write_cond; /* O.K. to write */
static pthread_cond_t read_cond; /* O.K. to read */
static int readers_done;
int *done;
static int num_readers;
void init_synch(readers)
int readers;
{
int i;
if (pthread_mutex_init(&mutex, pthread_mutexattr_default) == -1) {
perror("pthread_mutex_init");
exit(1);
}
if (pthread_cond_init(&write_cond, pthread_condattr_default) == -1) {
perror("pthread_cond_init");
exit(1);
}
if (pthread_cond_init(&read_cond, pthread_condattr_default) == -1) {
perror("pthread_cond_init");
exit(1);
}
num_readers = readers;
readers_done = num_readers;
if (!(done = (int *)malloc(num_readers * sizeof(int)))) {
perror("malloc");
exit(1);
}
for (i = 0; i < num_readers; i++) done[i] = 1;
}
void wait_for_consumers()
{
pthread_mutex_lock(&mutex);
if (readers_done != num_readers) {
pthread_cond_wait(&write_cond, &mutex);
}
pthread_mutex_unlock(&mutex);
}
void signal_consumers()
{
int i;
pthread_mutex_lock(&mutex);
readers_done = 0;
for (i = 0; i < num_readers; i++) done[i] = 0;
pthread_cond_broadcast(&read_cond);
pthread_mutex_unlock(&mutex);
}
void signal_producer(id)
int id;
{
pthread_mutex_lock(&mutex);
readers_done++;
if (readers_done == num_readers) {
pthread_cond_signal(&write_cond);
}
done[id] = 1;
pthread_mutex_unlock(&mutex);
}
void wait_for_producer(id)
int id;
{
pthread_mutex_lock(&mutex);
if (done[id]) pthread_cond_wait(&read_cond, &mutex);
pthread_mutex_unlock(&mutex);
}
/*
** Program to simulate a real-time system and measure and/or record
** 1. Device driver interrupt response time
** 2. Device driver interrupt service time
** 3. Task response time
**
** Each measured time is exagerated by a constant amount of time equal to the
** length of time it takes to make the measurement.
*/
#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <types.h>
#include <sched.h>
#define PRODUCER_PRIO 31
extern void producer();
extern void display(), consumer();
struct {
void (*f)(); /* task entry point */
int p_bias; /* priority relative to producer (always negative) */
} consumers[] = {
{ display, -1 },
{ consumer, -1 }
};
#define NCONSUMERS (sizeof consumers / sizeof consumers[0])
static void start_consumers()
{
int i;
pthread_attr_t attr;
pthread_t tid;
for (i = 0; i < NCONSUMERS; i++) {
pthread_attr_create(&attr);
pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
pthread_attr_setprio(&attr, PRODUCER_PRIO + consumers[i].p_bias);
if (pthread_create(&tid, attr, consumers[i].f, i) == -1) {
perror("pthread_create");
exit(1);
}
}
}
main(argc, argv)
int argc;
char *argv[];
{
unsigned long period;
char *ptr;
if (argc < 2 || argc > 3) {
fprintf(stderr, "Usage: %s timer_device [ period ]\n", argv[0]);
exit(1);
}
if (argc == 3) {
period = strtol(argv[2], &ptr, 0);
if (*ptr) {
(void) fprintf(stderr, "%s: invalid period %s\n",argv[0],argv[2]);
exit(1);
}
} else {
period = 0l;
}
if (setprio(0, PRODUCER_PRIO) == -1) {
perror("setprio");
exit(1);
}
init_synch(NCONSUMERS);
start_consumers();
init_timer(argv[1], period);
producer();
exit(0);
}
void producer()
{
for (;;) {
wait_for_interrupt();
signal_consumers();
wait_for_consumers();
}
}
/*
** Consumer which writes data to screen.
*/
#include <stdio.h>
#include <pthread.h>
#include <types.h>
#include <sched.h>
#include "timer.h"
static unsigned short min_bufs[2][NUM_TIMES];
static unsigned short max_bufs[2][NUM_TIMES];
static unsigned short *min;
static unsigned short *max;
static int overrun_counts[2];
static pthread_mutex_t mutexes[2];
static int fill_buf = 0, show_buf = 0;
static void reset_arrays(mins, maxs)
unsigned short *mins, *maxs;
{
int i;
for (i = 0; i < NUM_TIMES; i++) {
mins[i] = 0xffff;
maxs[i] = 0x0;
}
}
static void show()
{
int i;
unsigned short *min, *max;
for (;;) {
min = min_bufs[show_buf];
max = max_bufs[show_buf];
pthread_mutex_lock(&mutexes[show_buf]);
for (i = 0; i < NUM_TIMES; i++) {
unlocked_printf("%3u %3u | ", min[i], max[i]);
fflush(stdout);
}
unlocked_printf("%u\n", overrun_counts[show_buf]);
reset_arrays(min, max);
overrun_counts[show_buf] = 0;
pthread_mutex_unlock(&mutexes[show_buf]);
show_buf ^= 1;
}
}
static void create_show()
{
pthread_attr_t attr;
tid_t tid;
pthread_mutex_init(&mutexes[0], pthread_mutexattr_default);
pthread_mutex_init(&mutexes[1], pthread_mutexattr_default);
pthread_mutex_lock(&mutexes[0]);
pthread_attr_create(&attr);
pthread_attr_setinheritsched(&attr, PTHREAD_DEFAULT_SCHED);
pthread_attr_setprio(&attr, getprio(0) - 1);
if (pthread_create(&tid, attr, show, 0) == -1) {
perror("pthread_create");
exit(1);
}
}
void display(id)
int id;
{
int i, j;
unsigned long iterations;
unsigned long remaining;
reset_arrays(min_bufs[0], max_bufs[0]);
reset_arrays(min_bufs[1], max_bufs[1]);
min = min_bufs[fill_buf];
max = max_bufs[fill_buf];
printf("Dividing by %lu\n", period);
iterations = 5000000 / period;
if (!iterations) iterations = 1;
remaining = iterations;
create_show();
for (;;) {
wait_for_producer(id);
for (i = 0; i < NUM_TIMES; i++) {
min[i] = times[i] < min[i] ? times[i] : min[i];
max[i] = times[i] > max[i] ? times[i] : max[i];
}
overrun_counts[fill_buf] += overruns;
if (!--remaining) {
pthread_mutex_unlock(&mutexes[fill_buf]);
fill_buf ^= 1;
min = min_bufs[fill_buf];
max = max_bufs[fill_buf];
remaining = iterations;
pthread_mutex_lock(&mutexes[fill_buf]);
}
signal_producer(id);
}
}
void consumer(id)
int id;
{
for (;;) {
wait_for_producer(id);
signal_producer(id);
}
}
/*
** Device driver for the Industrial Computer Source model DCC20A
** timer/counter board based on four AMD Am9513 System Timing Controllers
**
** Configuration assumptions:
*/
#include <kernel.h>
#include <mem.h>
#include <file.h>
#include <errno.h>
#include "timer_ioctl.h"
#include "timer_info.h"
#include "am9513.h"
struct timer_statics {
unsigned long period;
unsigned long default_period;
int irq;
int closed;
int interrupt_sem;
unsigned int overruns;
unsigned short port;
unsigned short drt;
unsigned short ist_delta;
unsigned short short_period;
};
void timer_interrupt(s)
struct timer_statics *s;
{
am9513_command(s->port+1, CMD_SAVE | CMD_COUNTER(1));
if (s->interrupt_sem < 0) {
ssignal(&s->interrupt_sem);
s->drt = am9513_input(s->port);
am9513_command(s->port+1, CMD_SAVE | CMD_COUNTER(1));
s->ist_delta = am9513_input(s->port);
} else {
s->overruns++;
}
}
struct timer_statics *timer_install(info)
struct timer_info *info;
{
struct timer_statics *s;
int port;
/* reset the Am9513 (this will insure the interrupt is off) */
am9513_reset(info->port+1);
/* allocate the data structure to hold the static variables */
s = (struct timer_statics *)sysbrk((long)sizeof *s);
if (!s) return (struct timer_statics *)SYSERR;
/* initialize the static variables */
s->irq = info->irq;
s->port = info->port;
s->default_period = info->period;
s->closed = 1;
return s;
}
void timer_uninstall(s)
struct timer_statics *s;
{
sysfree(s, (long)sizeof *s);
}
int timer_open(s, devno, f)
struct timer_statics *s;
int devno;
struct file *f;
{
/* make sure the monor device number is 0 */
if (minor(devno)) {
pseterr(ENXIO);
return SYSERR;
}
/* if the device was closed reset the defaults and interrupt handling */
if (s->closed) {
s->closed = 0;
s->period = s->default_period;
s->interrupt_sem = 0;
iointset(s->irq, timer_interrupt, s);
(void) am9513_set_period(s->port+1, s->port, &s->period);
s->short_period = s->period > 0xFFFF ? 0xFFFF : s->period;
s->overruns = 0;
am9513_command(s->port+1,CMD_SET_DPR(ELEMENT_CMR,GROUP_CNTR(1)));
am9513_output(s->port,
CMR_GATE_EDGE_HIGH|CMR_SOURCE_F1|CMR_COUNT_REPEAT);
am9513_command(s->port+1,CMD_SET_DPR(ELEMENT_CLR,GROUP_CNTR(1)));
am9513_output(s->port, s->short_period);
am9513_command(s->port+1,CMD_SET_DPR(ELEMENT_CHR,GROUP_CNTR(1)));
am9513_command(s->port+1, CMD_LOAD_AND_ARM | CMD_COUNTER(1));
}
return OK;
}
int timer_close(s, f)
struct timer_statics *s;
struct file *f;
{
/* reset the Am9513 (this will insure the interrupt is off) */
am9513_reset(s->port+1);
s->closed = 1;
iointclr(s->irq);
return OK;
}
int timer_rws()
{
pseterr(EINVAL);
return SYSERR;
}
int timer_ioctl(s, f, command, arg)
struct timer_statics *s;
struct file *f;
int command;
void *arg;
{
int ps;
struct timer_measurements *m = (struct timer_measurements *)arg;
switch (command) {
case TIMER_WAIT_FOR_INT:
if (arg) {
if (wbounds(arg) < sizeof(struct timer_measurements)) {
pseterr(EFAULT);
return SYSERR;
}
disable(ps);
swait(&s->interrupt_sem, -1);
m->ist = s->drt - s->ist_delta;
m->drt = s->short_period - s->drt;
m->overruns = s->overruns;
s->overruns = 0;
restore(ps);
} else {
disable(ps);
swait(&s->interrupt_sem, -1);
s->overruns = 0;
restore(ps);
}
break;
case TIMER_PERIOD_SET:
if (wbounds(arg) < sizeof(long)) {
pseterr(EFAULT);
return SYSERR;
}
s->period = *(unsigned long *)arg;
if (am9513_set_period(s->port+1, s->port, &s->period) == -1) {
pseterr(EINVAL);
return SYSERR;
}
s->short_period = s->period > 0xFFFF ? 0xFFFF : s->period;
*(unsigned long *)arg = s->period;
am9513_command(s->port+1,CMD_SET_DPR(ELEMENT_CLR,GROUP_CNTR(1)));
am9513_output(s->port, s->short_period);
am9513_command(s->port+1,CMD_SET_DPR(ELEMENT_CHR,GROUP_CNTR(1)));
am9513_command(s->port+1, CMD_LOAD_AND_ARM | CMD_COUNTER(1));
break;
case TIMER_PERIOD_GET:
if (wbounds(arg) < sizeof(long)) {
pseterr(EFAULT);
return SYSERR;
}
*(unsigned long *)arg = s->period;
break;
case TIMER_READ:
disable(ps);
am9513_command(s->port+1, CMD_SAVE | CMD_COUNTER(1));
if (wbounds(arg) < sizeof(short)) {
restore(ps);
pseterr(EFAULT);
return SYSERR;
}
*(unsigned short *)arg = s->short_period - am9513_input(s->port);
restore(ps);
break;
default:
pseterr(EINVAL);
return SYSERR;
}
return OK;
}
#include <dldd.h>
static struct dldd entry_points = {
timer_open, /* open */
timer_close, /* close */
timer_rws, /* read */
timer_rws, /* write */
timer_rws, /* select */
timer_ioctl, /* ioctl */
timer_install, /* install */
timer_uninstall /* uninstall */
};
#include "am9513.h"
#define MAX_TIMER_VALUE ((1<<16)-1)
struct {
unsigned long divisor;
unsigned short scaler_mode;
unsigned short count_src;
} divisors[] = {
{ 1, MMR_SCALER_BINARY, CMR_SOURCE_F1 },
{ 10, MMR_SCALER_BCD, CMR_SOURCE_F2 },
{ 16, MMR_SCALER_BINARY, CMR_SOURCE_F2 },
{ 100, MMR_SCALER_BCD, CMR_SOURCE_F3 },
{ 256, MMR_SCALER_BINARY, CMR_SOURCE_F3 },
{ 1000, MMR_SCALER_BCD, CMR_SOURCE_F4 },
{ 4096, MMR_SCALER_BINARY, CMR_SOURCE_F4 },
{ 10000, MMR_SCALER_BCD, CMR_SOURCE_F5 },
{ 65536, MMR_SCALER_BINARY, CMR_SOURCE_F5 }
};
#define NDIVISORS (sizeof divisors / sizeof divisors[0])
void am9513_command(cmd_port, command)
unsigned short cmd_port;
unsigned char command;
{
asm {
mov DX, cmd_port[EBP]
mov AL, command[EBP]
out DX, AL
}
}
void am9513_output(data_port, data)
unsigned short data_port, data;
{
asm {
mov DX, data_port[EBP]
mov AX, data[EBP]
out DX, AL
shr AX, 8
out DX, AL
}
}
unsigned short am9513_input(data_port)
unsigned short data_port;
{
asm {
xor EAX, EAX
mov DX, data_port[EBP]
in AL, DX
mov BL, AL
in AL, DX
shl AX, 8
mov AL, BL
}
}
int am9513_set_period(cmd_port, data_port, p_period)
unsigned short cmd_port, data_port;
unsigned long *p_period;
{
unsigned long count;
int i;
count = *p_period;
for (i = 0; i < NDIVISORS; i++) {
if (count / divisors[i].divisor <= MAX_TIMER_VALUE) break;
}
if (i == NDIVISORS) return -1;
count /= divisors[i].divisor;
*p_period = count * divisors[i].divisor;
am9513_command(cmd_port, CMD_SET_DPR(ELEMENT_MMR, GROUP_CNTRL));
am9513_output(data_port, divisors[i].scaler_mode | MMR_DP_NOINC);
am9513_command(cmd_port, CMD_SET_DPR(ELEMENT_CMR, GROUP_CNTR(5)));
am9513_output(data_port,
divisors[i].count_src | CMR_COUNT_REPEAT | CMR_OUT_PULSE_HIGH);
am9513_command(cmd_port, CMD_SET_DPR(ELEMENT_CLR, GROUP_CNTR(5)));
am9513_output(data_port, count);
am9513_command(cmd_port, CMD_LOAD_AND_ARM | CMD_COUNTER(5));
return 0;
}